import os

import sys
import shutil
import re
import string
import sets
import codecs

from util import trackstr, sanitizeFileName, ShaggerVersion, mypopen, parseTrackNum, parseTrackNumFromTag
from stages import GlobalStage, Shagstage
from flac import FlacEncode, FlacTag

from config import Config

import musicbrainz2.disc as mbdisc
from musicbrainzdata import MBalbum
from mutagen.flac import FLAC #for prepare destination, needs fixing.

#FIXME: Should be RewindFiles
class RewidFiles(GlobalStage):
    suffix = FlacEncode.suffix
    def __init__(self, shagger):
        GlobalStage.__init__(self, shagger) 
    
    def preamble(self):
        return "Rewinding file names."
    
    def canWork(self):
        '''
        files = self.shagger.fileSubset("flac")
        
        if( len(files) == len(self.shagger.tracks)):
            return True
        print("wrong number of tracks")
        return False
        '''
        return True
    
    def work(self):
        files = self.shagger.fileSubset("flac")
        tracks = {}
        
        ok = True
        
        for file in files:
            tracknum = -1
            audio = FLAC( file )
            if(audio.has_key("tracknumber")):
                tracknum = parseTrackNumFromTag( audio["tracknumber"][0] )            
            else:
                tracknum = int(parseTrackNum(file))
            
            print("found track %d - %s" % (tracknum, file ))
            if (tracknum == None or tracknum < 0):
                self.shagger.log("can't find tracknum for file: %s" % file)
                ok = False
            try:
                self.shagger.tracks.index(tracknum)
            except Exception:
                self.shagger.log("release doesn't have track %f: %s" % (tracknum, file))
                ok = False
            else:
                tracks[tracknum] = file
                    
        for t in self.shagger.tracks:
            if(not tracks.has_key(t)):
                self.shagger.log("didn't find track %d" % t)
                ok = False
        
        if(ok == False):
            print("missing some shagger tracks: %s" % self.shagger.tracks)
            return False
        
        #ok we should have as many files as we have tracks. Hurrah.
        for track in tracks:
            
            target = self.shagger.trackfilename(track, self.suffix)        
            if(os.path.exists(target)):
                if(os.path.samefile(target, tracks[track])):
                    continue
                else:
                    #just to be cautious
                    self.shagger.log("Cannot move %s to %s due to collision!" % (tracks[track], target))
                return False
            shutil.move(tracks[track], target)
            
        self.shagger.log("Done rewinding files")
            
        
        return True

class PrepareDestination(GlobalStage):
    
    file = "targetdir"
    
    def __init__(self, shagger):
        GlobalStage.__init__(self, shagger) 
    
    def preamble(self):
        return "prepare destination dir"
    
    def canWork(self):
        file = os.path.join(self.shagger.dir(), self.file)
        if(os.path.exists(file)):
            return True
        
        files = self.shagger.fileSubset("flac")
        
        if( len(files) == 0):
            return False
        return True
    
    def work(self):
        file = os.path.join(self.shagger.dir(), self.file)
        if(os.path.exists(file)):
            f = codecs.open(file, "r", encoding="utf-8")
            targetpath1 = string.rstrip(f.read())
            f.close()
            
        else:
            
            files = self.shagger.fileSubset("flac")
            
            audio = FLAC( files[0] )
            
            targettail = None
            targetpath = None
            
            
            #Either this is tagged as compilation, or it has artist "Various Artists"
            #hopefully both are true.
            #NB: Fail if albumartist is not set - I'm not interested in ambiguous cases.
            if (audio.has_key("releasetype") and audio["releasetype"][0].lower() == "spokenword"):
                #spoken word...
                targettail = sanitizeFileName(audio["ALBUM"][0] ) 
                targetpath = os.path.join( Config["spokenword"],sanitizeFileName( audio["albumartist"][0]))
                 
            elif ((audio.has_key("releasetype") and audio["releasetype"][0].lower() == "compilation")
                or (audio.has_key("albumartist") and audio["albumartist"][0].lower() == "various artists")):
                #various artists / compilation
                targettail = sanitizeFileName(audio["ALBUM"][0])
                targetpath = os.path.join(Config["compilations"])
            else:
                if(audio.has_key("releasetype") and audio["releasetype"][0].lower() == "single"):
                    #mark singles since 
                    targettail = sanitizeFileName(audio["ALBUM"][0] + " [single]" )
                else:
                    targettail = sanitizeFileName(audio["ALBUM"][0] )
                targetpath = os.path.join( Config["targetdir"],sanitizeFileName( audio["albumartist"][0])) 
                
            
            if not os.access( targetpath, os.F_OK):
                #sledgehammer approach: can't read => dir doesn't exist.
                os.makedirs( targetpath )
            
            targetpath1 = os.path.join(targetpath, targettail)
            count = 0
            
            #now if this exists, we need to frig the tail
            while(os.path.exists(targetpath1)):
                print "Directory exists! %s" % targetpath1
                count = count + 1
                targetpath1 = os.path.join(targetpath, targettail+("_copy%d_" % count) )
            
            
            print "Using target path: %s" % targetpath1    
            
            if not self.practice:
                os.makedirs( targetpath1 )
                #Hurrah! we made it. Now stash the path somewhere.
                                
                f = codecs.open(file, "w", encoding="utf-8")
                f.write(targetpath1)
                f.close()
        
        self.shagger.setTargetPath(targetpath1)
        return True

class DeployDirectory(GlobalStage):
        
    file = "targetdir"
    
    def __init__(self, shagger):
        GlobalStage.__init__(self, shagger)
                       
    def preamble(self):
        return "Deploy directory to music collection"       

    def canWork(self):
        return True 
    
    def work(self):
        files = self.shagger.fileSubset("flac")
        
        audio = FLAC( files[0] )
        
        targettail = None
        targetpath = None
        
        
        #Either this is tagged as compilation, or it has artist "Various Artists"
        #hopefully both are true.
        #NB: Fail if albumartist is not set - I'm not interested in ambiguous cases.
        if (audio.has_key("releasetype") and audio["releasetype"][0].lower() == "spokenword"):
            #spoken word...
            targettail = sanitizeFileName(audio["ALBUM"][0] ) 
            targetpath = os.path.join( Config["spokenword"],sanitizeFileName( audio["albumartist"][0]))
             
        elif ((audio.has_key("releasetype") and audio["releasetype"][0].lower() == "compilation")
            or (audio.has_key("albumartist") and audio["albumartist"][0].lower() == "various artists")):
            #even here we must be careful. According to musicbrainz style guides, compilation inclodes "Anthologies" or "Best of"
            #releases. So need to do a manual check to see that all the artists are the same.
                        
            #various artists / compilation            
            targettail = sanitizeFileName(audio["ALBUM"][0])
            targetpath = os.path.join(Config["compilations"])
        else:
            if(audio.has_key("releasetype") and audio["releasetype"][0].lower() == "single"):
                #mark singles since 
                targettail = sanitizeFileName(audio["ALBUM"][0] + " [single]" )
            else:
                targettail = sanitizeFileName(audio["ALBUM"][0] )
            targetpath = os.path.join( Config["targetdir"],sanitizeFileName( audio["albumartist"][0]))
        
        if not os.access( targetpath, os.F_OK):                
            os.makedirs( targetpath )
            
        targetpath1 = os.path.join(targetpath, targettail)
        #This may seem bizzare but ultimately files are stored in ascii
        #Need to encode it as ascii, otherwise this will fail:
        # dir = u'D\xe9j\xe0 Vu' #from shagger tag
        # file = 'D\xe9j\xe0 Vu' #from OS operation
        # os.path.join( u'D\xe9j\xe0 Vu', 'D\xe9j\xe0 Vu' ) #dies horribly.
        targetpath1 = targetpath1.encode( Config["encoding"] )
        
        #Does the target directory exist?        
        if(os.path.exists(targetpath1)):
            if(os.path.samefile(targetpath1, self.shagger.dir())):
                #nothing to do!
                self.shagger.log("Already in: %s" % targetpath1)
                return True
            self.shagger.log("Directory exists! %s" % targetpath1)
            return False;
        self.shagger.log("Moving from %s to: %s" % (self.shagger.dir(), targetpath1) )
        shutil.move(self.shagger.dir(), targetpath1)
        return True
        
             
    
class FinalDestination(Shagstage):
    
    #previous = "tagged.flac" #
    previous = FlacTag.suffix    
    suffix = "done"
    
    def __init__(self, shagger, track):
        Shagstage.__init__(self, shagger, track)    
    
    def preamble(self):
        return "Rename track files"     
    
    def canWork(self):
        files = self.fetchFiles()
        for file in files:
            if file.endswith(self.previous):
                return True     
                    
    def work(self):
        if not self.canWork():
            return False
        
        previousfile = self.filename( self.previous )
        audio = FLAC( previousfile )
        
        filename = None
        
        if(audio.has_key("COMPILATION") and audio["COMPILATION"][0]=="1"):
            filename = "%02d - %s - %s.flac" % (self.track, sanitizeFileName(audio["ARTIST"][0]),sanitizeFileName(audio["title"][0]))
        else:
            filename = "%02d - %s - %s.flac" % (self.track, sanitizeFileName(audio["ARTIST"][0]), sanitizeFileName(audio["title"][0]))
        
        filename = filename.encode( Config["encoding"] )
        targetfile = os.path.join(self.shagger.dir(), filename)
        
        print( "Target: %s" % targetfile )
        
        if self.practice:
            return True
        
        if(os.path.exists(targetfile)):
            #just to be cautious
            self.shagger.log("Cannot move %s to %s due to collision!" % (previousfile, targetfile))
            return False
        
        shutil.move(previousfile, targetfile)
        '''
        f = open(self.filename(self.suffix), "w")
        f.close()
        '''
        
        return True
 
class MoveMiscGubbins(GlobalStage):
    #move anything else to the final place.   
    #for now just move cover.jpg
    file = "cover.jpg" #this would create circular inlude problem: FetchCoverArt.file 
    
    def __init__(self, shagger):
        GlobalStage.__init__(self, shagger)    
    
    def preamble(self):
        return "Copy misc gubbins to Final Destination"     
    
    def canWork(self):
        files = self.shagger.fileSubset()
        for file in files:
            if os.path.split( file )[1] == self.file:
                return True
        return False
             
                    
    def work(self):
        if not self.canWork():
            return False
        
        previousfile = self.filename( self.file )        
        targetfile = os.path.join(self.shagger.targetpath, self.file)
        
        print( "Target: %s" % targetfile )
        
        if self.practice:
            return True
        
        shutil.move(previousfile, targetfile)
        
        return True

class Tidy(GlobalStage):
    
    previous = FinalDestination.suffix
    
    def __init__(self, shagger):
        GlobalStage.__init__(self, shagger) 
    
    def preamble(self):
        return "Tidy"
    
    def canWork(self):
        files = self.shagger.fileSubset("")
        
        for file in files:
            if not file.endswith(self.previous):
                #does the file have no extension?
                if not os.path.split(file)[-1].find(".") < 0:
                    print "Can't tidy becasue of %s" % file
                    return False
            
        return True
    
    def work(self):
        if self.practice:
            return True
        
        if not self.canWork():
            return False
        
        shutil.rmtree(self.shagger.dir())
        return True
     